package com.example.gobang.api;

import com.example.gobang.game.*;
import com.example.gobang.model.User;
import com.example.gobang.model.UserMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;


@Component
public class GameApi extends TextWebSocketHandler {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private RoomManger roomManger;

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private UserMapper userMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        GameReadyResponse resp = new GameReadyResponse();
        //1.用户未登入情况
        User user = (User) session.getAttributes().get("user");
        if (user == null){
            resp.setOk(false);
            resp.setReason("用户未登入");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            return;
        }

        //2.用户是否在房间内
        Room room = roomManger.getRoomByUserId(user.getUserId());
        if (room == null){
            resp.setOk(false);
            resp.setReason("用户未匹配到！");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            session.close();
            return;
        }
        //3.用户多开情况
        if (onlineUserManager.getFromGameHall(user.getUserId()) != null
                || onlineUserManager.getFromGameRoom(user.getUserId()) != null){
            resp.setOk(false);
            resp.setReason("用户在其他地方登入！");
            resp.setMessage("repeatConnection");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            session.close();
            return;
        }
        //4.更新用户游戏状态
        onlineUserManager.enterGameRoom(user.getUserId(), session);

        // 5. 把两个玩家加入到游戏房间中.
        //    前面的创建房间/匹配过程, 是在 game_hall.html 页面中完成的.
        //    因此前面匹配到对手之后, 需要经过页面跳转, 来到 game_room.html 才算正式进入游戏房间(才算玩家准备就绪)
        //    当前这个逻辑是在 game_room.html 页面加载的时候进行的.
        //    执行到当前逻辑, 说明玩家已经页面跳转成功了!!

        //ai对战的房间
        if (room.isAi()){
            if (room.getUser1() == null){
                room.setUser1(user);
                User user2 = new User();
                user2.setUserId(-1);
                user2.setUsername("AI");
                room.setUser2(user2);
                room.setWhiteUser(user.getUserId());
                System.out.println("玩家 " + user.getUsername() + " 已经准备就绪! 作为玩家1");
            }
            noticeGameReady(room,room.getUser1(),room.getUser2());
            return;
        }
        //玩家对战的房间
        synchronized (room){
            if (room.getUser1() == null){
                room.setUser1(user);
                room.setWhiteUser(user.getUserId());
                System.out.println("玩家 " + user.getUsername() + " 已经准备就绪! 作为玩家1");
                return;
            }
            if (room.getUser2() == null){
                room.setUser2(user);
                // 当两个玩家都加入成功之后, 就要让服务器, 给这两个玩家都返回 websocket 的响应数据.
                // 通知这两个玩家说, 游戏双方都已经准备好了.
                System.out.println("玩家 " + user.getUsername() + " 已经准备就绪! 作为玩家2");
                // 通知玩家1
                noticeGameReady(room, room.getUser1(), room.getUser2());
                // 通知玩家2
                noticeGameReady(room, room.getUser2(), room.getUser1());
                return;
            }
            // 6. 此处如果又有玩家尝试连接同一个房间, 就提示报错.
            //    这种情况理论上是不存在的, 为了让程序更加的健壮, 还是做一个判定和提示.
            resp.setOk(false);
            resp.setReason("当前房间已满, 您不能加入房间");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
        }
    }

    private void noticeGameReady(Room room, User thisUser, User thatUser) throws IOException {
        GameReadyResponse resp = new GameReadyResponse();
        resp.setMessage("gameReady");
        resp.setOk(true);
        resp.setReason("");
        resp.setRoomId(room.getRoomId());
        resp.setThisUserId(thisUser.getUserId());
        resp.setThatUserId(thatUser.getUserId());
        resp.setWhiteUserId(room.getWhiteUser());
        // 把当前的响应数据传回给玩家.
        WebSocketSession webSocketSession = onlineUserManager.getFromGameRoom(thisUser.getUserId());
        webSocketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        User user = (User) session.getAttributes().get("user");
        if (user == null){
            return;
        }
        Room room = roomManger.getRoomByUserId(user.getUserId());
        room.putChess(message.getPayload());
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        User user = (User) session.getAttributes().get("user");
        if (user == null){
            return;
        }
        WebSocketSession tempSession = onlineUserManager.getFromGameRoom(user.getUserId());
        if (tempSession != session){
            System.out.println("当前的会话不是玩家游戏中的会话, 不做任何处理!");
            return;
        }
        onlineUserManager.exitGameRoom(user.getUserId());
        System.out.println("连接出错! userId=" + user.getUserId());

        noticeThatUserWin(user);

    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        User user = (User) session.getAttributes().get("user");
        if (user == null){
            return;
        }
        WebSocketSession tempSession = onlineUserManager.getFromGameRoom(user.getUserId());
        if (tempSession != session){
            System.out.println("当前的会话不是玩家游戏中的会话, 不做任何处理!");
            return;
        }
        onlineUserManager.exitGameRoom(user.getUserId());
        System.out.println("用户退出! userId=" + user.getUserId());
        noticeThatUserWin(user);
    }

    private void noticeThatUserWin(User user) throws IOException {
        //1.获取房间
        Room room = roomManger.getRoomByUserId(user.getUserId());
        if (room == null){
            System.out.println("当前房间已经释放！");
            return;
        }
        User thatUser = (user == room.getUser1() ? room.getUser2() : room.getUser1());
        //3.找到对手在线状态
        WebSocketSession session = onlineUserManager.getFromGameRoom(thatUser.getUserId());
        if (session == null){
            System.out.println("对手也离线了");
            return;
        }
        //4.给对手返回离线响应
        GameResponse resp = new GameResponse();
        resp.setMessage("putChess");
        resp.setUserId(thatUser.getUserId());
        resp.setWinner(thatUser.getUserId());
        resp.setCol(-1);
        resp.setRow(-1);
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));

        //5.更新玩家获胜信息
        userMapper.userWin(thatUser.getUserId());
        userMapper.userLose(user.getUserId());

        //6.释放房间对象
        roomManger.remove(room,room.getUser1().getUserId(),room.getUser2().getUserId());
    }
}

